/*
 * Copyright 2011-2012 Redia A/S
 * 
 * This file is part of Redias Library App for Android.
 *
 *  Redia Library App for Android is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  Redia Library App for Android is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *  
 *  You should have received a copy of the GNU General Public License
 *  along with Redia Library App for Android.  If not, see <http://www.gnu.org/licenses/>.
 */
package dk.redia.libraryapp.adapters;

import java.lang.ref.SoftReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import android.annotation.SuppressLint;
import android.database.DataSetObserver;
import dk.redia.lib.log.Log;
import android.view.View;
import android.widget.ListAdapter;
import dk.redia.libraryapp.net.RemoteListManager;
import dk.redia.libraryapp.net.RemoteListManagerListener;

@SuppressLint("UseSparseArrays") // DEBUG: I need to consider this I guess?

public abstract class RemoteListAdapter implements RemoteListManagerListener, ListAdapter {
	private List<AdapterStateListener> sizeListeners;
	private RemoteListManager<?> listManager;
	private DataSetObserverCollection observers;
//	private Map<String, SoftReference<View>> identifierViewCache;
//	private Map<Integer, SoftReference<View>> viewCache;
	private Map<String, View> identifierViewCache;
	private Map<Integer, View> viewCache;
	
	private static final String logTag = "RemoteListAdapter";

	public RemoteListAdapter(RemoteListManager<?> listManager) {
		sizeListeners = new ArrayList<AdapterStateListener>();
		this.observers = new DataSetObserverCollection();
		this.listManager = listManager;
		this.listManager.addListener(this);
//		this.viewCache = new HashMap<Integer, SoftReference<View>>();
//		this.identifierViewCache = new HashMap<String, SoftReference<View>>();
		this.viewCache = new HashMap<Integer, View>();
		this.identifierViewCache = new HashMap<String, View>();
	}
		
	
	public void reset() {
		listManager.reset();
		identifierViewCache.clear();
		viewCache.clear();
		refresh();
	}
	
	protected void setParam(String name, Object value) {
		listManager.setParam(name, value);
	}
	
	public View getItemView(int index) {
		if (viewCache.containsKey(index)) {
			return viewCache.get(index);
//			View view = viewCache.get(index).get();
//			if (view == null) {
//				viewCache.remove(index);
//			}
//			return view;
		} else {
			return null;
		}
	}
	
	public View getIdentifierView(String identifier) {
		if (identifierViewCache.containsKey(identifier)) {
			return identifierViewCache.get(identifier);
//			View view = identifierViewCache.get(identifier).get();
//			if (view == null) {
//				identifierViewCache.remove(identifier);
//			}
//			return view;
		} else {
			return null;
		}
	}
	
	public Object getExtraResultData(String key) {
		return listManager.getExtraResultData(key);
	}
	
	public void updateViewCache(int idx, String identifier, View v) {
		this.viewCache.put(idx, v);
//		this.viewCache.put(idx, new SoftReference<View>(v));
		if (identifier!=null) {
			this.identifierViewCache.put(identifier, v);
//			this.identifierViewCache.put(identifier, new SoftReference<View>(v));
		}
	}
	
	protected View getCachedView(int idx) {
		return this.viewCache.get(idx);
//		View view = this.viewCache.get(idx).get();
//		if (view == null) {
//			this.viewCache.remove(idx);
//		}
//		return view;
	}
	
	public void init() {
		listManager.init();
	}
	
	void ensureIndexLoad(int index) {
		listManager.ensureIndexLoad(index);
	}
	
	int getLoadState(int position) {
		return listManager.getLoadState(position);
	}
	
	public void addAdapterSizeListener(AdapterStateListener l) {
		sizeListeners.add(l);
	}
	
	public void removeAdapterSizeListener(AdapterStateListener l) {
		sizeListeners.remove(l);
	}
	
	private void notifyStateListenersSizeChanged(int length) {
		List<AdapterStateListener> cp = new ArrayList<AdapterStateListener>(sizeListeners);
		for (AdapterStateListener adapterSizeListener : cp) {
			adapterSizeListener.dataSetSizeChanged(length);
		}
	}
	
	private void notifyStateListenersChunkLoaded(int offset, int count) {
		List<AdapterStateListener> cp = new ArrayList<AdapterStateListener>(sizeListeners);
		for (AdapterStateListener adapterSizeListener : cp) {
			adapterSizeListener.chunkLoaded(offset, count);
		}
	}
	
	private void notifyStateListenersChunkLoadFailed(int offset, int count, String message) {
		List<AdapterStateListener> cp = new ArrayList<AdapterStateListener>(sizeListeners);
		for (AdapterStateListener adapterSizeListener : cp) {
			adapterSizeListener.chunkLoadFailed(offset, count, message);
		}
	}
	
	public int getCount() {
		return listManager.getSize();
	}

	public Object getItem(int arg0) {
		return this.listManager.getItem(arg0);
	}
	
	public long getItemId(int arg0) {
		return arg0;
	}

	public int getItemViewType(int arg0) {
		return IGNORE_ITEM_VIEW_TYPE;
	}

	public int getViewTypeCount() {
		return 1;
	}

	public boolean hasStableIds() {
		return false;
	}

	public boolean isEmpty() {
		return listManager.getSize()==0;
	}

	public void registerDataSetObserver(DataSetObserver arg0) {
		this.observers.registerObserver(arg0);
	}

	public void unregisterDataSetObserver(DataSetObserver arg0) {
		this.observers.unregisterObserver(arg0);
	}

	public boolean areAllItemsEnabled() {
		return true;
	}

	public boolean isEnabled(int arg0) {
		if (arg0>=listManager.getSize()) {
			throw new ArrayIndexOutOfBoundsException();
		} else {
			return true;
		}
	}
	
	public void listLengthChanged(int length) {
		Log.d(logTag, "List length changed to " + length);
		this.notifyStateListenersSizeChanged(length);
		this.observers.notifyObservers();
	}

	public void refresh() {
		this.observers.notifyObservers();
	}

	public void loadedStateChanged(List<Integer> indices, int state) {
		for (Integer index : indices) {
			Log.d(logTag, "Loaded state changed to " + state + " for index " + index);
			
			View v = getItemView(index);
			if (v!=null) {
				// There is currently a view associated with the specifed index
				Log.d(logTag, "Invalidating view associated with index " + index);
				getView(index, v, null).invalidate();
				//v.invalidate();
			} else {
				Log.d(logTag, "There is currently no view associated with index " + index);
			}
		}
		Log.d("khansen", "Size of viewCache: "+viewCache.size());
		Log.d("khansen", "Size of identifierViewCache:"+identifierViewCache.size());
	}
	
	public void chunkLoaded(int offset, int size) {
		notifyStateListenersChunkLoaded(offset, size);
	}

	public void chunkLoadFailed(int offset, int size, String message) {
		notifyStateListenersChunkLoadFailed(offset, size, message);
	}
	
	protected abstract View getViewByState(View v, int state);
}

